Jx.declare('Jx.lib.Xml', {

	$singleton: true,

	$helpers: {

		'String': 'Jx.lib.String'

	},

	_entityIndex: {

		'&': 'amp',

		'<': 'lt',

		'>': 'gt',

		'\'': 'apos',

		'"': 'quot'

	},

	_entityReverseLookup: undefined,

	_legalChars: /[\u0020\u000d\u000aA-Za-z0-9\-\(\)\+\,\.\/\:\=\?\;\!\*\#\@\$\_\%]/,

	_entityRe: /\&(\#([0-9a-fA-F]+)|[^\&\;]+)\;/g,

	constructor: function(){

		this.$super();

		//-- create entity index reverse lookup
		this._entityReverseLookup = this.createEntityListReverseLookup(this._entityIndex)

	},

	createEntityListReverseLookup: function(entities, target){

		var result = void(0);

		if (Jx.isObject(entities)){

			result = Jx.isObject(target) ?

				target

				:

				{};


			Jx.each(entities, function(n, v, o){

				if (o.hasOwnProperty(n) && Jx.isString(v, true)){

					this[v] = n;

				}

			}, result);

		}

		return result;

	},

	onUnescape: function(matched, ref, hex){

		var entities = arguments.callee.$entities;

		return hex ?

			String.fromCharCode( parseInt(hex, 16) )

			:

			entities.hasOwnProperty(ref) ?

				entities[ref]

				:

				matched;

	},

	escape: function(str, entities){

		var S = this.$String,

			result = '';

		if (Jx.isString(str)){

			Jx.assignIf(

				entities = Jx.isObject(entities) ?

					Jx.assign({}, entities)

					:

					{},

				this._entityIndex

			);

			var legalChars = this._legalChars;

			for(var chr, chars = [], l = str.length; l--;){

				chr = str.charAt(l);

				chars[l] = chr in entities ?

					'&'+entities[chr]+';'

					:

					!legalChars.test(chr) ?

						'&#' + S.pad( chr.charCodeAt(0), 4, '0') + ';'

						:

						chr;

			}

			result = chars.join('');

		}

		return result;

	},

	unescape: function(str, entities){

		var fn = this.onUnescape,

			result = '';

		if (Jx.isString(str, true)){

			this.createEntityListReverseLookup(this._entityIndex)


			fn.$entities = Jx.assignIf(

				entities = Jx.isObject(entities) ?

					this.createEntityListReverseLookup(entities)

					:

					{},

				this._entityReverseLookup

			);

			result = str.replace(this._entityRe, fn);

		}

		return result;

	},

	attributeValueEncode: function(str, entities){

		entities = Jx.isObject(entities) ?

			Jx.assign({}, entities)

			:

			{};

		entities[' '] = 'nbsp'

		return this.encode(str, entities);

	}



});
